package ip

import (
	"encoding/json"
	"fmt"
	"gitee.com/liumou_site/gns/eth"
	"gitee.com/liumou_site/logger"
	"io"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

// GetPublicIpv4Eth 获取指定网卡的公网IPv4地址。
//
// 参数:
//   - ethName: 要获取公网IP的网卡名称
//
// 返回值:
//   - net.IP: 获取到的公网IPv4地址
//   - error: 获取过程中出现的错误s
func GetPublicIpv4Eth(ethName string) (net.IP, error) {
	// 定义一个标志变量，用于判断指定的网卡名称是否存在。
	var exists bool

	// 创建一个Eth实例，不启用实时监控。
	get := eth.NewEth(false)

	// 获取系统中所有网卡的列表。
	ethList := get.GetEthList()

	// 遍历网卡列表，检查是否存在与ethName匹配的网卡。
	for _, eth_ := range ethList {
		if eth_ == ethName {
			exists = true
			break
		}
	}

	// 如果未找到匹配的网卡名称，返回错误。
	if !exists {
		return nil, fmt.Errorf("ethName not found: %s", ethName)
	}

	// 获取指定网卡的信息。
	info, err := get.GetEthInfoV4(ethName)
	if err != nil {
		return nil, err
	}

	// 创建一个绑定到网卡IP的客户端。
	client := createBoundClient(info.Ip[0].Ip)
	logger.Debug(info.Ip[0].Ip.String())
	// 尝试通过不同的方法获取公网IPv4地址。
	if ip, err := getPublicIpv4Sb(client); err == nil {
		logger.Debug("获取到本机公网IPv4地址:", ip)
		return net.ParseIP(ip), err
	}
	if ip, err := getIpv4Uomg(client); err == nil {
		logger.Debug("获取到本机公网IPv4地址:", ip)
		return net.ParseIP(ip), err
	}
	if ip, err := getPublicIP1Ipw(client); err == nil {
		logger.Debug("获取到本机公网IPv4地址:", ip)
		return net.ParseIP(ip), err
	}

	// 如果所有方法都失败，返回错误。
	return nil, fmt.Errorf("failed to get public IPv4 address")
}

// getPublicIP1Ipw 通过ipw.cn的API获取本机公网IPv4地址
//
// 实现细节:
//
// 1. 创建HTTP客户端并设置请求
//
// 2. 添加浏览器模拟请求头以避免被拦截
//
// 3. 发送请求并处理响应
//
// 返回值:
//
//   - string: 获取到的IP地址字符串
//   - error: 请求或解析过程中出现的错误
func getPublicIP1Ipw(client *http.Client) (string, error) {
	// 创建HTTP客户端
	//client := &http.Client{Timeout: 3 * time.Second}

	// 创建GET请求，访问ipw.cn的IP查询API
	req, err := http.NewRequest("GET", "https://test.ipw.cn/api/ip/myip", nil)
	if err != nil {
		log.Fatal(err)
	}

	// 设置请求头，模拟浏览器访问
	req.Header.Set("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
	// ... 其他请求头设置 ...

	// 发送HTTP请求
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer func(Body io.ReadCloser) {
		err = Body.Close()
		if err != nil {
			logger.Error(err.Error())
			return
		}
	}(resp.Body) // 确保响应体被关闭

	// 读取响应体内容
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	// 解析JSON响应到结构体
	var res ipv4IPW
	err = json.Unmarshal(bodyText, &res)
	if err != nil {
		return "", err
	}

	// 返回解析得到的IP地址
	return res.IP, nil
}

// getIpv4Uomg 通过uomg.com的API获取本机公网IPv4地址
// 返回值:
//   - string: 获取到的IP地址字符串
//   - error: 请求或解析过程中出现的错误
func getIpv4Uomg(client *http.Client) (string, error) {
	//client := &http.Client{Timeout: 3 * time.Second}
	// 创建HTTP GET请求，访问uomg.com的IP查询API
	req, err := http.NewRequest("GET", "https://api.uomg.com/api/visitor.info?skey=1", nil)
	if err != nil {
		log.Fatal(err)
	}

	// 设置请求头，模拟浏览器访问
	req.Header.Set("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
	// ... 其他请求头设置 ...

	// 发送HTTP请求
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer func(Body io.ReadCloser) {
		err = Body.Close()
		if err != nil {
			logger.Error(err.Error())
			return
		}
	}(resp.Body)

	// 读取响应体
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	// 解析JSON响应
	var res ipv4Uomg
	err = json.Unmarshal(bodyText, &res)
	if err != nil {
		return "", err
	}

	// 返回解析得到的IP地址
	return res.IP, nil
}

// GetPublicIpv4 获取本机的公网IPv4地址
//
// 该函数会尝试多个IP查询服务，按以下顺序尝试：
//
// 1. 首先尝试从 uomg.com 获取IP地址
//
// 2. 如果第一个服务失败，则尝试从 ipw.cn 获取IP地址
//
// 返回值：
//
//   - string: 获取到的IP地址字符串
//   - error: 如果所有服务都失败则返回最后一个错误
func GetPublicIpv4() (string, error) {
	client := &http.Client{Timeout: 3 * time.Second}
	if ip, err := getPublicIpv4Sb(client); err == nil {
		logger.Debug("获取到本机公网IPv4地址:", ip)
		return ip, err
	}
	if ip, err := getIpv4Uomg(client); err == nil {
		logger.Debug("获取到本机公网IPv4地址:", ip)
		return ip, err
	}
	if ip, err := getPublicIP1Ipw(client); err == nil {
		logger.Debug("获取到本机公网IPv4地址:", ip)
		return ip, err
	}
	return "", fmt.Errorf("failed to get public IPv4 address")
}

// getPublicIpv4Sb 通过ip.sb的API获取本机公网IPv4地址
//
// 实现细节:
//
// 1. 创建HTTP请求并设置详细的浏览器模拟请求头
//
// 2. 发送请求并处理响应
//
// 3. 解析返回的IP地址并验证有效性
//
// 注意:
//   - 函数名拼写有误(应为getPublicIpv4Sb)
//   - 函数目前没有返回值，调用方无法获取IP地址
func getPublicIpv4Sb(client *http.Client) (string, error) {
	//client := &http.Client{Timeout: 3 * time.Second}

	// 创建HTTP GET请求，访问ip.sb的IP查询API
	req, err := http.NewRequest("GET", "https://api-ipv4.ip.sb/ip", nil)
	if err != nil {
		// handle err
		return "", err
	}

	// 设置详细的浏览器模拟请求头
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
	req.Header.Set("Cache-Control", "max-age=0")
	req.Header.Set("Priority", "u=0, i")
	req.Header.Set("Sec-Ch-Ua", "\"Microsoft Edge\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"")
	req.Header.Set("Sec-Ch-Ua-Mobile", "?0")
	req.Header.Set("Sec-Ch-Ua-Platform", "\"Windows\"")
	req.Header.Set("Sec-Fetch-Dest", "document")
	req.Header.Set("Sec-Fetch-Mode", "navigate")
	req.Header.Set("Sec-Fetch-Site", "cross-site")
	req.Header.Set("Sec-Fetch-User", "?1")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0")

	// 发送HTTP请求
	resp, err := client.Do(req)
	if err != nil {
		logger.Error(err)
		return "", err
	}

	// 确保在函数结束时关闭响应体
	defer func(Body io.ReadCloser) {
		err = Body.Close()
		if err != nil {
			logger.Error(err.Error())
			return
		}
	}(resp.Body)

	// 读取响应体内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		logger.Error(err)
		return "", err
	}

	// 移除IPv6地址后的换行符，并解析IP地址
	ipStr := strings.TrimSpace(string(body))

	// 验证IP地址有效性
	ip := net.ParseIP(ipStr)
	if ip == nil {
		logger.Warn("无法从接口获取本机IP")
		logger.Debug(ipStr)
		return "", fmt.Errorf("invalid IP address: %s", ipStr)
	}
	return ipStr, nil
}

// createBoundClient 创建一个绑定到特定源IP的HTTP客户端。
// 这个函数的目的是为了在发送HTTP请求时，指定请求发出的源IP地址。
// 参数:
//
//	ip net.IP: 发起HTTP请求的源IP地址。
//
// 返回值:
//
//	*http.Client: 绑定到指定源IP的HTTP客户端。
func createBoundClient(ip net.IP) *http.Client {
	// 创建自定义传输
	transport := &http.Transport{
		DialContext: (&net.Dialer{
			LocalAddr: &net.TCPAddr{
				IP:   ip, // 指定源IP
				Port: 0,  // 系统自动分配端口
			},
			Timeout:   3 * time.Second,
			KeepAlive: 30 * time.Second,
		}).DialContext,
	}

	// 返回绑定到自定义传输的HTTP客户端
	return &http.Client{
		Transport: transport,
		Timeout:   3 * time.Second,
	}
}
